package com.unswift.cloud.utils;

import java.lang.reflect.Field;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.unswift.annotation.api.Api;
import com.unswift.annotation.api.ApiField;
import com.unswift.annotation.api.ApiMethod;
import com.unswift.cloud.annotation.logger.Compare;
import com.unswift.cloud.cache.ICacheAdapter;
import com.unswift.cloud.enums.OperatorTypeEnum;
import com.unswift.cloud.pojo.Pojo;
import com.unswift.utils.ClassUtils;
import com.unswift.utils.DateUtils;
import com.unswift.utils.NumberUtils;
import com.unswift.utils.ObjectUtils;
import com.unswift.utils.StringUtils;

@Api(value="操作日志公共类", author = "unswift", date = "2023-12-10", version = "1.0.0")
public final class LoggerUtils {

	private final static Logger logger = LoggerFactory.getLogger(LoggerUtils.class);
	
	@ApiField("操作日志本地对象")
	private static ThreadLocal<Map<String, Object>> threadLocal = new ThreadLocal<Map<String, Object>>(); 
	
	@ApiMethod(value="设置日志所属模块", params = @ApiField("操作的模块"))
	public static void setModule(String module) {
		Map<String, Object> local = threadLocal.get();
		if(ObjectUtils.isEmpty(local)) {
			local=new HashMap<String, Object>();
			threadLocal.set(local);
		}
		local.put("module", module);
	}
	
	@ApiMethod(value="获取日志所属模块", returns = @ApiField("操作的模块"))
	public static String getModule() {
		Map<String, Object> local = threadLocal.get();
		if(ObjectUtils.isNotEmpty(local)) {
			return (String)local.get("module");
		}
		return null;
	}
	
	@ApiMethod(value="设置原数据，因为@OperatorLogger注解所声明的方法只有最新数据，没有原数据，所以需要设置原数据", params = @ApiField("原数据"))
	public static void setOriginalData(Object originalData) {
		Map<String, Object> local = threadLocal.get();
		if(ObjectUtils.isEmpty(local)) {
			local=new HashMap<String, Object>();
			threadLocal.set(local);
		}
		local.put("original", originalData);
	}
	
	@ApiMethod(value="设置原数据，因为@OperatorLogger注解所声明的方法只有最新数据，没有原数据，所以需要设置原数据", returns = @ApiField("原数据"))
	public static Object getOriginalData() {
		Map<String, Object> local = threadLocal.get();
		if(ObjectUtils.isNotEmpty(local)) {
			return local.get("original");
		}
		return null;
	}
	
	@ApiMethod(value="设置日志数据id", params = @ApiField("数据id"))
	public static void setId(Long id) {
		Map<String, Object> local = threadLocal.get();
		if(ObjectUtils.isEmpty(local)) {
			local=new HashMap<String, Object>();
			threadLocal.set(local);
		}
		local.put("dataId", id);
	}
	
	@ApiMethod(value="获取日志数据id", returns = @ApiField("数据id"))
	public static Long getId() {
		Map<String, Object> local = threadLocal.get();
		if(ObjectUtils.isNotEmpty(local)) {
			return (Long)local.get("dataId");
		}
		return null;
	}
	
	@ApiMethod("删除操作日志变量")
	public static void remove() {
		threadLocal.remove();
	}
	
	@ApiMethod(value="将对象转为日志内容", params = {@ApiField("需要转换的对象，需继承Pojo实体")}, returns = @ApiField("日志内容"))
	public static <T extends Pojo> String toLoggerString(T pojo) {
		return toLoggerString(pojo, null, null);
	}
	
	@ApiMethod(value="将对象转为日志内容", params = {@ApiField("需要转换的对象，需继承Pojo实体"), @ApiField("比较的pojo"), @ApiField("新数据或原数据")}, returns = @ApiField("日志内容"))
	public static <T extends Pojo> String toLoggerString(T pojo, Pojo comparePojo, Boolean newOrOriginal) {
		if(ObjectUtils.isNull(pojo)) {
			return null;
		}
		StringBuilder content=new StringBuilder();
		List<Field> fieldList=ClassUtils.getFieldList(pojo.getClass());
		String fieldComment;
		for (Field field : fieldList) {
			Compare compare = field.getAnnotation(Compare.class);
			if(ObjectUtils.isNotEmpty(compare)) {
				fieldComment=compare.value();
				if(ObjectUtils.isEmpty(fieldComment)) {
					ApiField apiField = field.getAnnotation(ApiField.class);
					fieldComment=apiField.value();
				}
				if(ObjectUtils.isNotEmpty(fieldComment)) {
					Object fieldValue = ClassUtils.get(pojo, field);
					String fieldValueContent;
					if(ClassUtils.isSuperClass(field.getType(), List.class) && ObjectUtils.isNotEmpty(compare.pkFieldName()) && ObjectUtils.isNotEmpty(comparePojo)) {
						Object compareFieldValue = ClassUtils.get(comparePojo, field.getName());
						fieldValueContent = listToLogger((List<?>)fieldValue, (List<?>)compareFieldValue, newOrOriginal, compare.pkFieldName(), fieldComment);
						if(ObjectUtils.isNotEmpty(fieldValueContent)) {
							content.append(fieldValueContent);
							content.append("，");
						}
					}else {
						if(ClassUtils.isSuperClass(field.getType(), List.class)) {
							fieldValueContent=listToLogger((List<?>)fieldValue, fieldComment, OperatorTypeEnum.CREATE);
							if(ObjectUtils.isNotEmpty(fieldValueContent)) {
								content.append(fieldComment).append("：");
								content.append(fieldValueContent);
								content.append("，");
							}
						}else {
							content.append(fieldComment).append("：");
							if(ClassUtils.isSuperClass(field.getType(), Pojo.class)){
								if(ObjectUtils.isNotEmpty(fieldValue)) {
									fieldValue = ClassUtils.invoke(fieldValue, "toLoggerString");
									content.append(fieldValue);
								}else {
									content.append(fieldValue);
								}
							}else {
								fieldValue = fieldValueFormat(compare, fieldValue);
								content.append(StringUtils.toString(fieldValue, "空"));
							}
							content.append("，");
						}
					}
				}
			}
		}
		if(content.length()>0) {
			content.deleteCharAt(content.length()-1);
		}
		return content.toString();
	}

	@ApiMethod(value="字段值进行翻译", params = {@ApiField("比较注解"), @ApiField("字段值")})
	private static Object fieldValueFormat(Compare compare, Object fieldValue) {
		if(ObjectUtils.isNotEmpty(fieldValue)) {
			if(fieldValue instanceof Date) {
				if(ObjectUtils.isNotEmpty(compare.format())) {
					fieldValue=DateUtils.format((Date)fieldValue, compare.format());
				}else {
					fieldValue=DateUtils.format((Date)fieldValue, "yyyy-MM-dd HH:mm:ss");
				}
			}else if(fieldValue instanceof Number) {
				if(ObjectUtils.isNotEmpty(compare.format())) {
					fieldValue=NumberUtils.format((Number)fieldValue, compare.format());
				}
			}else if(ObjectUtils.isNotEmpty(compare.translateType())) {
				ICacheAdapter cacheAdapter = BeanUtils.getBean(ICacheAdapter.class);
				fieldValue=cacheAdapter.findDictionaryValueByKey(compare.translateType(), ServletUtils.getRequest().getHeader("Language"), fieldValue.toString());
			}
		}
		return fieldValue;
	}
	
	@ApiMethod(value="两个Pojo进行比较，并返回差异字符串", params = {@ApiField("原pojo"), @ApiField("新pojo")}, returns = @ApiField("差异字符串"))
	public static <O extends Pojo, N extends Pojo> String compareTo(O originalPojo, N newPojo) {
		if(ObjectUtils.isNull(originalPojo) || ObjectUtils.isNull(newPojo)) {
			return null;
		}
		StringBuilder content=new StringBuilder();
		List<Field> fieldList=ClassUtils.getFieldList(newPojo.getClass());
		String fieldComment;
		for (Field field : fieldList) {
			Compare compare = field.getAnnotation(Compare.class);
			if(ObjectUtils.isNotEmpty(compare)) {
				fieldComment=compare.value();
				if(ObjectUtils.isEmpty(fieldComment)) {
					ApiField apiField = field.getAnnotation(ApiField.class);
					fieldComment=apiField.value();
				}
				if(ObjectUtils.isNotEmpty(fieldComment)) {
					Object newFieldValue = ClassUtils.get(newPojo, field);
					Object originalFieldValue = ClassUtils.get(originalPojo, field.getName());
					String newFieldValueContent="空";
					String originalFieldValueContent="空";
					if(ClassUtils.isSuperClass(field.getType(), List.class)) {
						if(ObjectUtils.isNotEmpty(compare.pkFieldName())) {
							listToLogger((List<?>)originalFieldValue, (List<?>)newFieldValue, compare.pkFieldName(), content, fieldComment);
							content.append("，");
							continue;
						}else {
							newFieldValueContent=listToLogger((List<?>)newFieldValue, fieldComment, OperatorTypeEnum.CREATE);
							originalFieldValueContent=listToLogger((List<?>)originalFieldValue, fieldComment, OperatorTypeEnum.DELETE);
						}
					}else if(ClassUtils.isSuperClass(field.getType(), Pojo.class)){
						if(ObjectUtils.isNotEmpty(newFieldValue)) {
							newFieldValueContent = ClassUtils.invoke(newFieldValue, "toLoggerString");
						}else {
							newFieldValueContent = "空";
						}
						if(ObjectUtils.isNotEmpty(originalFieldValue)) {
							originalFieldValueContent = ClassUtils.invoke(originalFieldValue, "toLoggerString");
						}else {
							originalFieldValueContent = "空";
						}
					}else {
						newFieldValue=fieldValueFormat(compare, newFieldValue);
						newFieldValueContent=StringUtils.toString(newFieldValue, "空");
						originalFieldValue=fieldValueFormat(compare, originalFieldValue);
						originalFieldValueContent=StringUtils.toString(originalFieldValue, "空");
					}
					if(!ObjectUtils.equals(newFieldValueContent, originalFieldValueContent, false)) {
						content.append(fieldComment).append("由【").append(originalFieldValueContent).append("】变更为【");
						content.append(newFieldValueContent).append("】，");
					}
				}
			}
		}
		if(content.length()>0) {
			content.deleteCharAt(content.length()-1);
		}
		return content.toString();
	}
	
	@ApiMethod(value="将列表转换为日志内容", params = {@ApiField("需要转换的列表"), @ApiField("列表字段中文描述"), @ApiField("操作类型")}, returns = @ApiField("日志内容"))
	private static String listToLogger(List<?> list, String fieldComment, OperatorTypeEnum operatorType) {
		String newFieldValueContent=null;
		if(ObjectUtils.isNotEmpty(list)) {
			StringBuilder listContent=new StringBuilder();
			for (Object item : list) {
				listContent.append(operatorType.getValue()).append(fieldComment).append("【");
				if(item instanceof Pojo) {
					Object itemString = ClassUtils.invoke(item, "toLoggerString");
					listContent.append(itemString);
				}else {
					listContent.append(StringUtils.toString(list, "空"));
				}
				listContent.append("】,");
			}
			if(listContent.length()>0) {
				listContent.deleteCharAt(listContent.length()-1);
			}
			newFieldValueContent=listContent.toString();
		}else {
			newFieldValueContent="";
		}
		return newFieldValueContent;
	}
	
	@ApiMethod(value="将列表转换为日志内容", params = {@ApiField("原数据列表"), @ApiField("新数据列表"), @ApiField("列表数据唯一属性字段"), @ApiField("日志对比内容"), @ApiField("列表字段中文描述")})
	private static void listToLogger(List<?> originalData, List<?> newData, String pkFieldName, StringBuilder content, String fieldComment) {
		if(ObjectUtils.isEmpty(originalData) && ObjectUtils.isEmpty(newData)) {
			return ;
		}
		if(ObjectUtils.isEmpty(originalData)) {
			content.append(listToLogger(newData, fieldComment, OperatorTypeEnum.CREATE));
		}else if(ObjectUtils.isEmpty(newData)) {
			content.append(listToLogger(originalData, fieldComment, OperatorTypeEnum.DELETE));
		}else {
			boolean addContent=false;
			List<?> findNew;
			int i=0;
			for (Object original : originalData) {
				i++;
				Object pkValue=ClassUtils.get(original, pkFieldName);
				if(ObjectUtils.isEmpty(pkValue)) {
					logger.error("无法获取主键值，类："+original.getClass().getName()+",位于原列表的第"+i+"个元素");
					continue;
				}
				findNew=newData.stream().filter(n -> pkValue.equals(ClassUtils.get(n, pkFieldName))).collect(Collectors.toList());
				if(ObjectUtils.isEmpty(findNew)) {
					content.append(OperatorTypeEnum.DELETE.getValue()).append(fieldComment).append("【");
					if(original instanceof Pojo) {
						Object itemString = ClassUtils.invoke(original, "toLoggerString");
						content.append(itemString);
					}else {
						content.append(StringUtils.toString(original, "空"));
					}
					content.append("】，");
					addContent=true;
				}else {
					Object findNewOne=findNew.get(0);
					String originalContent=null;
					if(original instanceof Pojo) {
						originalContent = ClassUtils.invoke(original, "toLoggerString", new Class<?>[] {Pojo.class, boolean.class}, findNewOne, false);
					}else {
						originalContent = StringUtils.toString(original, "空");
					}
					String newContent=null;
					if(findNewOne instanceof Pojo) {
						newContent = ClassUtils.invoke(findNewOne, "toLoggerString", new Class<?>[] {Pojo.class, boolean.class}, original, true);
					}else {
						newContent = StringUtils.toString(findNewOne, "空");
					}
					if(!originalContent.equals(newContent)) {
						content.append(OperatorTypeEnum.UPDATE.getValue()).append(fieldComment).append("信息【").append(originalContent);
						content.append("】为【").append(newContent);
						content.append("】，");
						addContent=true;
					}
				}
			}
			Object findOriginal;
			i=0;
			for (Object object : newData) {
				i++;
				Object pkValue=ClassUtils.get(object, pkFieldName);
				if(ObjectUtils.isEmpty(pkValue)) {
					logger.error("无法获取主键值，类："+object.getClass().getName()+",位于新列表的第"+i+"个元素");
					continue;
				}
				findOriginal=originalData.stream().filter(o -> pkValue.equals(ClassUtils.get(o, pkFieldName))).collect(Collectors.toList());
				if(ObjectUtils.isEmpty(findOriginal)) {
					String newContent=null;
					if(object instanceof Pojo) {
						newContent = ClassUtils.invoke(object, "toLoggerString");
					}else {
						newContent = StringUtils.toString(object, "空");
					}
					content.append(OperatorTypeEnum.CREATE.getValue()).append(fieldComment).append("【").append(newContent).append("】");
					content.append("，");
					addContent=true;
				}
			}
			if(addContent && content.length()>0) {
				content.deleteCharAt(content.length()-1);
			}
		}
	}
	
	@ApiMethod(value="将列表转换为日志内容", params = {@ApiField("字段列表"), @ApiField("对比数据"), @ApiField("新数据或原数据"), @ApiField("列表数据唯一属性字段"), @ApiField("字段描述")}, returns = @ApiField("日志内容"))
	private static String listToLogger(List<?> fieldData, List<?> compareData, Boolean newOrOriginal, String pkFieldName, String fieldComment) {
		if(ObjectUtils.isEmpty(fieldData)) {
			return String.format("%s：%s", fieldComment,"空");
		}
		StringBuilder fieldContent=new StringBuilder();
		String pojoContent, compareContent;
		if(ObjectUtils.isEmpty(compareData)) {
			if(newOrOriginal) {
				fieldContent.append(listToLogger(fieldData, fieldComment, OperatorTypeEnum.CREATE));
			}else {
				fieldContent.append(listToLogger(fieldData, fieldComment, OperatorTypeEnum.DELETE));
			}
		}else {
			int i=0;
			List<?> compare;
			for (Object object : fieldData) {
				i++;
				Object pkValue=ClassUtils.get(object, pkFieldName);
				if(ObjectUtils.isEmpty(pkValue)) {
					logger.error("无法获取主键值，类："+object.getClass().getName()+",位于"+(newOrOriginal?"新":"原")+"列表的第"+i+"个元素");
					continue;
				}
				compare=compareData.stream().filter(o -> pkValue.equals(ClassUtils.get(o, pkFieldName))).collect(Collectors.toList());
				if(ObjectUtils.isEmpty(compare)) {
					if(newOrOriginal) {
						fieldContent.append(OperatorTypeEnum.CREATE.getValue()).append(fieldComment).append("【");
					}else {
						fieldContent.append(OperatorTypeEnum.DELETE.getValue()).append(fieldComment).append("【");
					}
					if(object instanceof Pojo) {
						pojoContent = ClassUtils.invoke(object, "toLoggerString");
					}else {
						pojoContent = StringUtils.toString(object, "空");
					}
					fieldContent.append(pojoContent);
					fieldContent.append("】，");
				}else {
					Object compareFirst=compare.get(0);
					if(object instanceof Pojo) {
						pojoContent = ClassUtils.invoke(object, "toLoggerString", new Class<?>[] {Pojo.class, boolean.class}, compareFirst, newOrOriginal.booleanValue());
					}else {
						pojoContent = StringUtils.toString(object, "空");
					}
					if(compareFirst instanceof Pojo) {
						compareContent = ClassUtils.invoke(compareFirst, "toLoggerString", new Class<?>[] {Pojo.class, boolean.class}, object, newOrOriginal.booleanValue());
					}else {
						compareContent = StringUtils.toString(compareFirst, "空");
					}
					if(!pojoContent.equals(compareContent)) {
						fieldContent.append(OperatorTypeEnum.UPDATE.getValue()).append(fieldComment).append("【").append(newOrOriginal?"新数据为：":"原数据为：");
						fieldContent.append(pojoContent);
						fieldContent.append("】，");
					}
				}
			}
			if(fieldContent.length()>0) {
				fieldContent.deleteCharAt(fieldContent.length()-1);
			}
		}
		return fieldContent.toString();
	}
}
